package com.hp.bon.logreverse;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.ocs.diameter.ProtocolConstants;
import com.hp.ocs.diameter.message.AVP;
import com.hp.ocs.diameter.message.DictionaryManager;
import com.hp.ocs.diameter.message.Message;
import com.hp.ocs.diameter.message.dictionary.Avp;

public class DCCDecoder implements IDecoder {
	private static SimpleDateFormat sd4AVP = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
	private static final Logger LOG = LoggerFactory.getLogger(DCCDecoder.class);

	int idx = 0;
	protected MsgInfo msgInfo = null;

	private static DictionaryManager _dic = DictionaryManager.getInstance();

	public boolean isMatch(ReverseLogEvent logEvent) {
		if ((logEvent.moreStrList == null) || (logEvent.moreStrList.size() < 4))
			return false;
		if (!((String) logEvent.moreStrList.get(0)).startsWith("==========[Diameter")) {
			return false;
		}
		this.msgInfo = new MsgInfo(logEvent);
		return true;
	}

	public boolean isParse() throws Exception {
		String header1 = this.msgInfo.logEvent.headStr;
		String header2 = (String) this.msgInfo.logEvent.moreStrList.get(0);

		String logDateStr = header1.substring(0, 23);
		this.msgInfo.logDate = ReverseLogEvent.sd4Log.parse(logDateStr);
		int idxSendOrReceiv = header1.indexOf("Send", 23);
		if (idxSendOrReceiv > 0) {
			this.msgInfo.isRecv = false;
		} else {
			idxSendOrReceiv = header1.indexOf("Receiv", 23);
			if (idxSendOrReceiv < 0) {
				LOG.warn("not have SendOrReceiv flag:" + header1);
				return false;
			}
			this.msgInfo.isRecv = true;
		}

		this.msgInfo.nodeName = header1.substring(header1.indexOf('[', idxSendOrReceiv) + 1, header1.indexOf(']', idxSendOrReceiv));
		if (header2.contains("CCR")) {
			this.msgInfo.isRequest = true;
		} else if (header2.contains("CCA")) {
			this.msgInfo.isRequest = false;
		} else {
			LOG.info("not ccr or cca:" + header1);
			return false;
		}
		return true;
	}

	public MsgInfo parse() throws Exception {
		KeyValue curKv = null;
		ArrayList<KeyValue> values = new ArrayList<KeyValue>(this.msgInfo.logEvent.moreStrList.size() - 3);
		int avpNum = this.msgInfo.logEvent.moreStrList.size() - 1;
		for (int i = 2; i < avpNum; i++) {
			String str = (String) this.msgInfo.logEvent.moreStrList.get(i);
			int numT = 0;
			while ((str.length() > numT) && (str.charAt(numT) == '\t')) {
				numT++;
			}
			int idx1 = str.indexOf('(');
			int idx2 = str.indexOf(")=", idx1 + 4);
			if (idx2 < 0) {
				if (!str.isEmpty()) {
					curKv.value = (curKv.value + "\n" + str);
				}
			} else {
				String avpName = idx1 > 0 ? str.substring(numT, idx1) : str.substring(numT, idx2);
				String value = str.substring(idx2 + 2);
				curKv = new KeyValue(avpName, value, numT);
				values.add(curKv);
			}
		}
		Message msg = new Message();
		msg._rt0 = this.msgInfo.logDate.getTime();
		msg.header().setRequest(this.msgInfo.isRequest);
		msg.header().setProxiable(true);
		msg.header().setApplicationID(4);
		msg.header().setCommandCode(272);
		for (this.idx = 0; this.idx < values.size(); this.idx += 1) {
			AVP avp = makeAVP(values, (KeyValue) values.get(this.idx));
			if (avp != null)
				msg.add(avp);
		}
		this.msgInfo.msg = msg;
		return this.msgInfo;
	}

	public MsgInfo getMsgInfo() {
		return this.msgInfo;
	}

	private AVP makeAVP(ArrayList<KeyValue> values, KeyValue kv) {
		// step1 查找avpType
		Avp avpType = _dic.avpType(0, kv.key);
		if (avpType == null) {
			// LOG.warn("undefined avp name:" + kv.key + ",lineNum =" +
			// this.msgInfo.logEvent.startlineNum);
			return null;
		}
		// step2 跟据不用的avpType进行转换
		Object avpValue = null;
		switch (avpType.getDataFormat()) {
		case Grouped:
			ArrayList<AVP> subavps = new ArrayList<AVP>();
			for (++idx; idx < values.size(); ++idx) {
				KeyValue kv4Child = values.get(idx);
				if (kv4Child.depth <= kv.depth) {
					--idx;// 回退一步，退出group循环
					break;
				}
				AVP avp = makeAVP(values, kv4Child);
				if (avp != null) {
					subavps.add(avp);
				}
			}
			avpValue = subavps.toArray(new AVP[subavps.size()]);
			break;
		case Time:
			try {
				avpValue = sd4AVP.parse(kv.value);
			} catch (ParseException e) {
				LOG.warn("ParseException:" + kv.key);
			}
			break;
		default:
			int idx = -1;
			if (avpType.getEnum().size() > 0) {
				idx = kv.value.indexOf('-');
			}
			if (idx > 0)
				avpValue = kv.value.substring(0, idx);
			else
				avpValue = kv.value;
		}

		// step3 构造AVP
		try {
			return _dic.makeAVP(ProtocolConstants.DIAMETER_APPLICATION_COMMON, kv.key, avpValue);
		} catch (Exception e) {
			LOG.warn("create avp failed:key=" + kv.key + ",value=" + avpValue, e);
		}
		return null;
	}

	public class KeyValue {
		String key;
		String value;
		int depth;

		public KeyValue(String avpName, String value, int depth) {
			this.key = avpName;
			this.value = value;
			this.depth = depth;
		}

		public String toString() {
			return this.depth + ": " + this.key + "=" + this.value;
		}
	}
}